/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.ibatis.extension.enums;

import com.je.ibatis.extension.keygen.sql.*;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 数据库方言
 *
 * @author wangmm@ketr.com.cn
 * @date 2019/11/22
 */
public enum DbType {
    /**
     * MYSQL
     */
    MYSQL("mysql", "MySql数据库", "dialects.MySqlDialect"),
    /**
     * MARIADB
     */
    MARIADB("mariadb", "MariaDB数据库", "dialects.MariaDBDialect"),
    /**
     * ORACLE
     */
    ORACLE("oracle", "Oracle数据库", new OracleKeySqlGenerator(), "dialects.OracleDialect"),
    /**
     * DB2
     */
    DB2("db2", "DB2数据库", new DB2KeySqlGenerator(), "dialects.DB2Dialect"),
    /**
     * H2
     */
    H2("h2", "H2数据库", new H2KeySqlGenerator(), "dialects.H2Dialect"),
    /**
     * HSQL
     */
    HSQL("hsql", "HSQL数据库", "dialects.HSQLDialect"),
    /**
     * SQLITE
     */
    SQLITE("sqlite", "SQLite数据库", "dialects.SQLiteDialect"),
    /**
     * POSTGRE
     */
    POSTGRE_SQL("postgresql", "Postgre数据库", new PostgreKeySqlGenerator(), "dialects.PostgreDialect"),
    /**
     * SQLSERVER2005
     */
    SQL_SERVER2005("sqlserver2005", "SQLServer2005数据库", "dialects.SQLServer2005Dialect"),
    /**
     * SQLSERVER
     */
    SQL_SERVER("sqlserver", "SQLServer数据库", "dialects.SQLServerDialect"),
    /**
     * DM
     */
    DM("dm", "达梦数据库", new DMDialectKeySqlGenerator(),"dialects.DmDialect"),
    /**
     * xugu
     */
    XU_GU("xugu", "虚谷数据库", "dialects.XuGuDialect"),
    /**
     * Kingbase
     */
    KINGBASEES("kingbasees", "人大金仓数据库", new KingbaseESKeySqlGenerator(), "dialects.KingbaseESDialect"),
    /**
     * oscar
     */
    OSCAR("oscar", "神通数据库", new OscarDialectKeySqlGenerator(), "dialects.OscarDialect"),
    /**
     * UNKONWN DB
     */
    OTHER("other", "其他数据库", "dialects.UnknownDialect");

    private static Map<String, DbType> DB_CACHE_MAP = new ConcurrentHashMap<>();

    static {
        for (DbType dbType : DbType.values()) {
            DB_CACHE_MAP.put(dbType.getDb().toLowerCase(), dbType);
        }
    }

    /**
     * 数据库名称
     */
    private final String db;
    /**
     * 描述
     */
    private final String desc;
    /**
     * Sql主键生成器
     */
    private KeySqlGenerator keySqlGenerator;
    /**
     * 分页方言
     */
    private String dialect;

    DbType(String db, String desc, String dialect) {
        this.db = db;
        this.desc = desc;
        this.dialect = dialect;
    }

    DbType(String db, String desc, KeySqlGenerator keySqlGenerator, String dialect) {
        this.db = db;
        this.desc = desc;
        this.keySqlGenerator = keySqlGenerator;
        this.dialect = dialect;
    }

    /**
     * 获取数据库类型
     *
     * @param dbType 数据库类型字符串
     */
    public static DbType getDbType(String dbType) {
        return DB_CACHE_MAP.getOrDefault(dbType.toLowerCase(), OTHER);
    }

    public static DbType getDbTypeByUrl(String jdbcUrl) {
        Assert.isTrue(!StringUtils.isEmpty(jdbcUrl), "Error: The jdbcUrl is Null, Cannot read database type");
        if (jdbcUrl.contains(":mysql:") || jdbcUrl.contains(":cobar:")) {
            return DbType.MYSQL;
        } else if (jdbcUrl.contains(":mariadb:")) {
            return DbType.MARIADB;
        } else if (jdbcUrl.contains(":oracle:")) {
            return DbType.ORACLE;
        } else if (jdbcUrl.contains(":sqlserver:") || jdbcUrl.contains(":microsoft:")) {
            return DbType.SQL_SERVER2005;
        } else if (jdbcUrl.contains(":sqlserver2012:")) {
            return DbType.SQL_SERVER;
        } else if (jdbcUrl.contains(":postgresql:")) {
            return DbType.POSTGRE_SQL;
        } else if (jdbcUrl.contains(":hsqldb:")) {
            return DbType.HSQL;
        } else if (jdbcUrl.contains(":db2:")) {
            return DbType.DB2;
        } else if (jdbcUrl.contains(":sqlite:")) {
            return DbType.SQLITE;
        } else if (jdbcUrl.contains(":h2:")) {
            return DbType.H2;
        } else if (jdbcUrl.contains(":dm:")) {
            return DbType.DM;
        } else if (jdbcUrl.contains(":xugu:")) {
            return DbType.XU_GU;
        } else if (jdbcUrl.contains(":kingbase:") || jdbcUrl.contains(":kingbase8:")) {
            return DbType.KINGBASEES;
        } else if (jdbcUrl.contains(":oscar:")) {
            return DbType.OSCAR;
        } else {
            return DbType.OTHER;
        }
    }

    public String getDb() {
        return db;
    }

    public String getDesc() {
        return desc;
    }

    public String getDialect() {
        return dialect;
    }

    public void setDialect(String dialect) {
        this.dialect = dialect;
    }

    public KeySqlGenerator getKeySqlGenerator() {
        return keySqlGenerator;
    }

    public void setKeySqlGenerator(KeySqlGenerator keySqlGenerator) {
        this.keySqlGenerator = keySqlGenerator;
    }
}
